//----------------------------------------------------------------------------------------------
//	Filename:	NullDevice.cpp
//	Author:		Sandro Spina
//	Date:		17/01/2012
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
#include "Device/NullDevice.h"

#include "Image/Image.h"
#include "Image/ImageIO.h"

#include "Spectrum/Spectrum.h"

using namespace Illumina::Core;
//----------------------------------------------------------------------------------------------
NullDevice::NullDevice(int p_nWidth, int p_nHeight)
	: m_pImage(new Image(p_nWidth, p_nHeight))	
{ }
//----------------------------------------------------------------------------------------------
NullDevice::NullDevice(const std::string &p_strName, int p_nWidth, int p_nHeight)
	: IDevice(p_strName) 
	, m_pImage(new Image(p_nWidth, p_nHeight))	
{ }
//----------------------------------------------------------------------------------------------
NullDevice::~NullDevice() 
{
	delete m_pImage;
}
//----------------------------------------------------------------------------------------------
int NullDevice::GetWidth(void) const { 
	return m_pImage->GetWidth(); 
}
//----------------------------------------------------------------------------------------------
int NullDevice::GetHeight(void) const { 
	return m_pImage->GetHeight(); 
}
//----------------------------------------------------------------------------------------------
IDevice::AccessType NullDevice::GetAccessType(void) const {
	return IDevice::ReadWrite;
}
//----------------------------------------------------------------------------------------------
bool NullDevice::Open(void) { 
	return true; 
}
//----------------------------------------------------------------------------------------------
void NullDevice::Close(void) { }
//----------------------------------------------------------------------------------------------
void NullDevice::BeginFrame(void) { }
//----------------------------------------------------------------------------------------------
void NullDevice::EndFrame(void)  { }
//----------------------------------------------------------------------------------------------
void NullDevice::Set(int p_nX, int p_nY, const Spectrum &p_spectrum) {
	m_pImage->Set(p_nX, p_nY, RGBPixel(p_spectrum[0], p_spectrum[1], p_spectrum[2]));
}
//----------------------------------------------------------------------------------------------
void NullDevice::Set(float p_fX, float p_fY, const Spectrum &p_spectrum) {
	Set((int)p_fX, (int)p_fY, p_spectrum); 
}
//----------------------------------------------------------------------------------------------
void NullDevice::Get(int p_nX, int p_nY, Spectrum &p_spectrum) const
{
	const RGBPixel pixel = m_pImage->Get(p_nX, p_nY);
	p_spectrum.Set(pixel.R, pixel.G, pixel.B);
}
//----------------------------------------------------------------------------------------------
void NullDevice::Get(float p_fX, float p_fY, Spectrum &p_spectrum) const
{
	// TODO: Provide option to enable bilinear interpolation
	const RGBPixel pixel = m_pImage->Get((int)p_fX, (int)p_fY);
	p_spectrum.Set(pixel.R, pixel.G, pixel.B);
}
//----------------------------------------------------------------------------------------------
Spectrum NullDevice::Get(int p_nX, int p_nY) const
{
	const RGBPixel pixel = m_pImage->Get(p_nX, p_nY);
	return Spectrum(pixel.R, pixel.G, pixel.B);
}
//----------------------------------------------------------------------------------------------
Spectrum NullDevice::Get(float p_fX, float p_fY) const
{
	const RGBPixel pixel = m_pImage->Get((int)p_fX, (int)p_fY);
	return Spectrum(pixel.R, pixel.G, pixel.B);
}
//----------------------------------------------------------------------------------------------
void NullDevice::WriteRadianceBufferToDevice(int p_nRegionX, int p_nRegionY, int p_nRegionWidth, int p_nRegionHeight, 
	RadianceBuffer *p_pRadianceBuffer, int p_nDeviceX, int p_nDeviceY)
{
	int width = m_pImage->GetWidth(),
		height = m_pImage->GetHeight();

	for (int srcY = p_nRegionY, dstY = p_nDeviceY; srcY < p_pRadianceBuffer->GetHeight(); ++srcY, ++dstY)
	{
		for (int srcX = p_nRegionX, dstX = p_nDeviceX; srcX < p_pRadianceBuffer->GetWidth(); ++srcX, ++dstX)
		{
			this->Set(width - (dstX + 1), height - (dstY + 1), p_pRadianceBuffer->Get(srcX, srcY).Final);
		}
	}
}
//----------------------------------------------------------------------------------------------